#include <stdio.h>
#include <getopt.h>
#include <string.h>
#include <unistd.h>
#include "../hdr/base64.h"

#define MAX_FILENAME_LENGTH 256
#define ENCODE 1
#define DECODE 2
#define DEFAULT_INPUT "stdin"
#define DEFAULT_OUTPUT "stdout"

int show_help();
int show_version();

int main(int argc, char** argv) 
{
	FILE* input = stdin, *output = stdout;
	
	/* Declaracion de variables de getopt. */
	const char* opt_string = "Vhi:o:a:";
	const struct option opt_long[] = 
					{ { "version", 0, NULL, 'V' }, 
					{ "help", 0, NULL, 'h' }, 
					{ "input", 1, NULL, 'i' },
					{ "output", 1, NULL, 'o' }, 
					{ "action", 1, NULL, 'a' }, 
					{ NULL, 0, NULL, 0 } };
	int opt_next = getopt_long(argc, argv, opt_string, opt_long, NULL);
	char input_file[MAX_FILENAME_LENGTH];
	char output_file[MAX_FILENAME_LENGTH];
	int accion = ENCODE;
	strcpy(input_file, DEFAULT_INPUT);
	strcpy(output_file, DEFAULT_OUTPUT);

	/* Bucle de getopt para procesar los parametros de la llamada. */
	while(opt_next != -1) 
	{
		switch(opt_next) 
		{
			case 'h':
				show_help();
				return 0;
			case 'V':
				show_version();
				return 0;
			case 'i':
				if (optarg != NULL && strcmp(optarg, "-") != 0)
				{
					strncpy(input_file, optarg, MAX_FILENAME_LENGTH);
					input = fopen(input_file, "rb");
					if(input == NULL)
					{
						fprintf(stderr, "Error: no se pudo abrir %s.\n", input_file);
						return -1;
					}
				}
				break;
			case 'o':
				if (optarg != NULL && strcmp(optarg, "-") != 0) 
				{
					strncpy(output_file, optarg, MAX_FILENAME_LENGTH);
					output = fopen(output_file, "wb");
					if(output == NULL)
					{
						fprintf(stderr, "Error: no se pudo abrir %s.\n", output_file);
						return -1;
					}
				}
				break;
			case 'a':
				if (optarg == NULL)
					accion = ENCODE;
				else 
				{
					if (strcmp(optarg, "encode") == 0)
						accion = ENCODE;
					else if (strcmp(optarg, "decode") == 0)
						accion = DECODE;
					else
					{
						fprintf(stderr, "Error: \"%s\": accion invalida. -h o --help para ver la ayuda.\n", optarg);
						return -1;
					}
				}
				break;
			}
		opt_next = getopt_long(argc, argv, opt_string, opt_long, NULL);
	}

	/* Bloque principal*/
	int err_code;	
	switch (accion) 
	{
		case ENCODE:
			err_code = base64_encode(fileno(input), fileno(output));
			break;
		case DECODE:
			err_code = base64_decode(fileno(input), fileno(output));
			break;
	}
	if (err_code > 0)
		printf("\nError: %s", errmsg[err_code - 1]);

	printf("\n");
	fclose(input);
	fclose(output);
	
	return 0;
}

int show_help() 
{
	printf("Uso: ./tp0 [args]\n");
	printf("Argumentos:\n");
	printf("\t-V, --version\tMuestra la version de la aplicacion.\n");
	printf("\t-h, --help\tMuestra esta informacion de ayuda.\n");
	printf("\t-i, --input\tDefine el archivo de entrada (default: stdin).\n");
	printf("\t-o, --output\tDefine el archivo de salida (default: stdout).\n");
	printf("\t-a, --action\tDefine la accion a realizar: encode (default) o decode.\n");
	return 0;
}

int show_version() 
{
	printf("66.20 - Organizacion de Computadoras\n");
	printf("Trabajo Practico Nro.1a: Infraestructura Basica\n");
	printf("Base64 Encoder/Decoder: version 2.0 (29/05/2012)\n");
	return 0;
}
